/*
 *  TI_Pixelator.cpp
 *
 *  Created by Pat Long (plong0) on 02/02/09.
 *  Copyright 2009 Tangible Interaction Inc. All rights reserved.
 *
 */
#include "TI_Pixelator.h"

TI_Pixelator::TI_Pixelator(){
	this->init();
}

TI_Pixelator::TI_Pixelator(int pixelWidth, int pixelHeight){
	this->init(pixelWidth, pixelHeight);
}

TI_Pixelator::~TI_Pixelator(){
	if(this->originalImage != NULL){
		delete this->originalImage;
	}
	if(this->pixelatedImage != NULL){
		delete this->originalImage;
	}
	if(this->pixels != NULL){
		delete this->pixels;
	}
}

void TI_Pixelator::init(int pixelWidth, int pixelHeight){
	this->pixelWidth = pixelWidth;
	this->pixelHeight = pixelHeight;
	this->originalImage = this->pixelatedImage = NULL;
	this->pixelRows = 0;
	this->pixelCols = 0;
	this->pixels = NULL;
}

void TI_Pixelator::refreshPixels(){
	if(this->originalImage != NULL){
		this->pixelateImage(this->originalImage);
	}
}

void TI_Pixelator::setPixelWidth(int pixelWidth, bool refresh){
	if(pixelWidth < 1){
		pixelWidth = 1;
	}
	this->pixelWidth = pixelWidth;
	if(refresh){
		this->refreshPixels();
	}
}

void TI_Pixelator::setPixelHeight(int pixelHeight, bool refresh){
	if(pixelHeight < 1){
		pixelHeight = 1;
	}
	this->pixelHeight = pixelHeight;
	if(refresh){
		this->refreshPixels();
	}
}

void TI_Pixelator::setPixelSize(int pixelWidth, int pixelHeight, bool refresh){
	this->setPixelWidth(pixelWidth, false);
	this->setPixelHeight(pixelHeight, false);
	if(refresh){
		this->refreshPixels();
	}
}

ofImage* TI_Pixelator::pixelateImage(ofImage* originalImage){
	if(this->originalImage != originalImage){
		if(this->originalImage != NULL){
			delete this->originalImage;
		}
		this->originalImage = originalImage;
	}
	int width = originalImage->width;
	int height = originalImage->height;
	int ofType = originalImage->type;
	int bpp = originalImage->bpp / 8;

	if(this->pixelHeight > 0){
		this->pixelRows = (int)ceil((float)height / (float)this->pixelHeight);
	}
	else{
		this->pixelRows = height;
	}
	if(this->pixelWidth > 0){
		this->pixelCols = (int)ceil((float)width / (float)this->pixelWidth);
	}
	else{
		this->pixelCols = width;
	}
	
	if(this->pixels != NULL){
		for(int i=0; i < this->pixelCols; i++){
			for(int j=0; j < this->pixelRows; j++){
				delete this->pixels[i][j];
			}
			delete this->pixels[i];
		}
		delete this->pixels;
	}
	this->pixels = new int**[this->pixelCols];
	for(int i=0; i < this->pixelCols; i++){
		this->pixels[i] = new int*[this->pixelRows];
		for(int j=0; j < this->pixelRows; j++){
			this->pixels[i][j] = new int[bpp];
		}
	}
	
	unsigned char* unpixelated = originalImage->getPixels();
	unsigned char* pixelated = new unsigned char[width*height*bpp];
	float averageRGB[bpp];
	int cPixelWidth, cPixelHeight;
	for(int i=0; i < width; i+=this->pixelWidth){
		for(int j=0; j < height; j+=this->pixelHeight){
			for(int bit=0; bit < bpp; bit++){
				averageRGB[bit] = 0.0;
			}
			
			cPixelWidth = cPixelHeight = 0;
			for(int x=i; x < i+this->pixelWidth && x < width; x++){
				cPixelWidth++;
				for(int y=j; y < j+this->pixelHeight && y < height; y++){
					if(x == i){
						cPixelHeight++;
					}
					for(int bit=0; bit < bpp; bit++){
						averageRGB[bit] += unpixelated[(y*width+x)*bpp+bit];
					}
				}
			}

			for(int bit=0; bit < bpp; bit++){
				averageRGB[bit] /= cPixelWidth * cPixelHeight;
				this->pixels[i/this->pixelWidth][j/this->pixelHeight][bit] = averageRGB[bit];
			}

			for(int x=i; x < i+this->pixelWidth && x < width; x++){
				for(int y=j; y < j+this->pixelHeight && y < height; y++){
					for(int bit=0; bit < bpp; bit++){
						pixelated[(y*width+x)*bpp+bit] = averageRGB[bit];
					}
				}
			}
		}
	}
	
	if(this->pixelatedImage == NULL){
		this->pixelatedImage = new ofImage();
	}
	else{
		this->pixelatedImage->clear();
	}
	this->pixelatedImage->allocate(width, height, ofType);
	this->pixelatedImage->setFromPixels(pixelated, width, height, ofType);
	
	delete pixelated;
	
	return this->pixelatedImage;
}

ofImage* TI_Pixelator::pixelateScreen(int x, int y, int width, int height){
	ofImage* screenCap = new ofImage();
	screenCap->grabScreen(x, y, width, height);
	return this->pixelateImage(screenCap);
}

ofImage* TI_Pixelator::pixelateScreen(ofRectangle* area){
	return this->pixelateScreen(area->x, area->y, area->width, area->height);
}

void TI_Pixelator::draw(int x, int y){
	this->drawPixelated(x, y);
}

void TI_Pixelator::drawOriginal(int x, int y){
	if(this->originalImage != NULL){
		this->originalImage->draw(x, y);
	}
}

void TI_Pixelator::drawPixelated(int x, int y){
	if(this->pixelatedImage != NULL){
		this->pixelatedImage->draw(x, y);
	}
}
